
#include <assert.h>
#include <stdlib.h>
#include "utility.h"
#include "qr-common.h"
#include "rs-block.h"

RSBlock* rs_block_new(int version, int ec_level, unsigned char* data)
{
	RSBlock* rs_block;

	if(qr_check_version(version) < 0 || qr_check_ec_level(ec_level) < 0 || NULL == data)
	{
		RES_NULL("Argument is invalid.");
	}

	rs_block = (RSBlock*)malloc(sizeof(RSBlock));
	if(NULL == rs_block)
	{
		RES_NULL("Invoke malloc error.");
	}
	rs_block->_block_count1 = qr_ecc_block_count1(version, ec_level);
	rs_block->_block_count2 = qr_ecc_block_count2(version, ec_level);
	rs_block->_data_length1 = qr_ecc_data_length1(version, ec_level);
	rs_block->_data_length2 = qr_ecc_data_length2(version, ec_level);
	rs_block->_ecc_length = qr_ecc_ecc_length(version, ec_level);
	rs_block->_entire_data_length = rs_block->_block_count1 * rs_block->_data_length1 + rs_block->_block_count2 * rs_block->_data_length2;
	rs_block->_entire_ecc_length = (rs_block->_block_count1 + rs_block->_block_count2) * rs_block->_ecc_length;
	rs_block->_data = data;
	rs_block->_ecc = (unsigned char*)malloc(rs_block->_ecc_length * sizeof(unsigned char));
	if(NULL == rs_block->_ecc)
	{
		free(rs_block);
		RES_NULL("Invoke malloc error.");
	}
	return rs_block;
}

void rs_block_destroy(RSBlock* rs_block)
{
	if(rs_block != NULL)
	{
		if(rs_block->_data != NULL)
		{
			free(rs_block->_data);
		}
		if(rs_block->_ecc != NULL)
		{
			free(rs_block->_ecc);
		}
		free(rs_block);
	}
}

int rs_block_entire_count(RSBlock* rs_block)
{
	int entire_data_length, entire_ecc_length;

	if(NULL == rs_block)
	{
		RES_INVAL("Argument is invalid.");
	}
	entire_data_length = rs_block->_entire_data_length;
	entire_ecc_length = rs_block->_entire_ecc_length;
	if(entire_data_length <= 0 || entire_ecc_length <= 0)
	{
		RES_INVAL("Argument is invalid.");
	}

	return (entire_data_length + entire_ecc_length);
}

unsigned char rs_block_get_code(RSBlock* rs_block, int index)
{
	int entire_data_length, entire_ecc_length;
	int block_count1, block_count2, block_count;
	int data_length1, data_length2, ecc_length;
	int column, row;
	unsigned char result;

	assert(rs_block != NULL);
	assert(rs_block->_data != NULL && rs_block->_ecc != NULL);
	entire_data_length = rs_block->_entire_data_length;
	entire_ecc_length = rs_block->_entire_ecc_length;
	assert(entire_data_length > 0 && entire_ecc_length > 0);
	assert(index >= 0 && index < entire_data_length + entire_ecc_length);

	block_count1 = rs_block->_block_count1;
	block_count2 = rs_block->_block_count2;
	block_count = block_count1 + block_count2;
	data_length1 = rs_block->_data_length1;
	data_length2 = rs_block->_data_length2;
	ecc_length = rs_block->_ecc_length;
	if(index < entire_data_length)
	{
		column = index / block_count;
		row = index % block_count;
		if(row < block_count1 && column >= data_length1)
		{
			row += block_count1;
		}
		assert((row < block_count1 && column < data_length1) || (row >= block_count1 && row < block_count && column < data_length2));
		if(row < block_count1)
		{
			result = rs_block->_data[row * data_length1 + column];
		}
		else
		{
			assert(row < block_count);
			result = rs_block->_data[block_count1 * data_length1 + (row - block_count1) * data_length2 + column];
		}
	}
	else
	{
		assert(index < entire_data_length + entire_ecc_length);
		index -= entire_data_length;
		column = index / block_count;
		row = index % block_count;
		assert(row < block_count && column < ecc_length);
		result = rs_block->_ecc[row * ecc_length + column];
	}
	return result;
}

